package org.eclipse.mylyn.rememberthemilk.ui.wizards;

import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.util.StatusHandler;
import org.eclipse.mylyn.internal.tasks.core.TaskRepositoryManager;
import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin;
import org.eclipse.mylyn.rememberthemilk.core.RTMCorePlugin;
import org.eclipse.mylyn.rememberthemilk.core.RTMRepositoryConnector;
import org.eclipse.mylyn.rememberthemilk.core.RTMRepositoryQuery;
import org.eclipse.mylyn.rememberthemilk.core.client.RTMClient;
import org.eclipse.mylyn.rememberthemilk.core.exceptions.RTMException;
import org.eclipse.mylyn.rememberthemilk.core.model.RTMSearch;
import org.eclipse.mylyn.rememberthemilk.core.model.RTMSearchFilter;
import org.eclipse.mylyn.rememberthemilk.core.model.RTMSearchFilter.CompareOperator;
import org.eclipse.mylyn.rememberthemilk.ui.RTMUIPlugin;
import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositoryQueryPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.ReopenEditorMenu;
import org.eclipse.ui.progress.IProgressService;

public class RtmCustomQueryPage extends AbstractRepositoryQueryPage {
	
	private static final String TITLE = "Enter query parameters";
	private static final String DESCRIPTION = "If attributes are blank or stale press the Update button.";
	private static final String TITLE_QUERY_TITLE = "Query Title:";
	
	protected final static String PAGE_NAME = "RTMSearchPage"; //$NON-NLS-1$
	private static final String SEARCH_URL_ID = PAGE_NAME + ".SEARCHURL";
	
	private static final String[] DEFAULT_STATUS_SELECTION = new String[] { "Incomplete", };
	
	private static final int LIST_HEIGHT = 60;
	
	private Map<String, SearchField> searchFieldByName = new HashMap<String, SearchField>();
	
	private IRepositoryQuery query;
	
	private TextSearchField summaryField;
	
	private TextSearchField descriptionField;
	
	private ListSearchField rtmStatusField;
	
	private ListSearchField rtmListsField;
	
	private Button updateButton;
	
	private Text titleText;
	
	private boolean firstTime = true;

//	public RtmCustomQueryPage(TaskRepository repository, AbstractRepositoryQuery query) {
//		super(TITLE);
//
//		this.repository = repository;
//		this.query = (RTMRepositoryQuery) query;
//
//		setTitle(TITLE);
//		setDescription(DESCRIPTION);
//	}

	public RtmCustomQueryPage(TaskRepository repository, String pageName, IRepositoryQuery query) {
		//this(repository, null);
		super(pageName, repository, query);
		
		this.query = query;
	}
	
	@Override
	public void setVisible(boolean visible) {
		super.setVisible(visible);

//		if (scontainer != null) {
//			scontainer.setPerformActionEnabled(true);
//		}

		if (visible && firstTime) {
			firstTime = false;
			if (!hasAttributes()) {
				// delay the execution so the dialog's progress bar is visible
				// when the attributes are updated
				Display.getDefault().asyncExec(new Runnable() {
					public void run() {
						if (getControl() != null && !getControl().isDisposed()) {
							initializePage();
						}
					}

				});
			} else {
				// no remote connection is needed to get attributes therefore do
				// not use delayed execution to avoid flickering
				initializePage();
			}
		}
	}

	private void initializePage() {
		updateAttributesFromRepository(false);
		boolean restored = (query != null);
		if (inSearchContainer()) {
			restored |= restoreWidgetValues();
		}
		// initialize with default values
//		if (!restored) {
//			rtmStatusField.selectItems(DEFAULT_STATUS_SELECTION);
//		}
	}
	
	private boolean restoreWidgetValues() {
		IDialogSettings settings = getDialogSettings();
		String repoId = "." ;//+ repository.getUserName();

		String searchUrl = settings.get(SEARCH_URL_ID + repoId);
		if (searchUrl == null) {
			return false;
		}

		restoreWidgetValues(new RTMSearch(searchUrl));
		return true;
	}
	private void restoreWidgetValues(RTMSearch search) {
		java.util.List<RTMSearchFilter> filters = search.getFilters();
		for (RTMSearchFilter filter : filters) {
			SearchField field = searchFieldByName.get(filter.getFieldName());
			if (field != null) {
				field.setFilter(filter);
			} else {
				//TODO: fix logging
				//StatusHandler.log("Ignoring invalid search filter: " + filter, this);
			}
		}
	}
	
	@Override
	public void saveState() {
		String repoId = ".";// + repository.getUrl();
		IDialogSettings settings = getDialogSettings();
		settings.put(SEARCH_URL_ID + repoId, getRTMSearch().toQuery());
	}
	
	private boolean hasAttributes() {
		RTMRepositoryConnector connector = (RTMRepositoryConnector) TasksUiPlugin.getRepositoryManager()
				.getRepositoryConnector(RTMCorePlugin.REPOSITORY_KIND);
//		try {
			//RTMClient client = connector.getClientManager().getRepository(repository);
			return false; //TODO: fix this .client.hasAttributes();
//		} catch (MalformedURLException e) {
//			return false;
//		}
	}
	
	
	public void createControl(Composite parent) {
		Composite control = new Composite(parent, SWT.NONE);
		GridData gd = new GridData(GridData.FILL_BOTH);
		control.setLayoutData(gd);
		GridLayout layout = new GridLayout(4, false);
		if (inSearchContainer()) {
			layout.marginWidth = 0;
			layout.marginHeight = 0;
		}
		control.setLayout(layout);

		createTitleGroup(control);

		summaryField = new TextSearchField("name");
		summaryField.createControls(control, "Name");

		descriptionField = new TextSearchField("tag");
		descriptionField.createControls(control, "Tags");

		createOptionsGroup(control);

		if (query != null) {
			titleText.setText(query.getSummary());
			restoreWidgetValues(new RTMSearch(query.getUrl()));
		}

		setControl(control);
	}
	
	private void createTitleGroup(Composite control) {
		if (inSearchContainer()) {
			return;
		}

		Label titleLabel = new Label(control, SWT.NONE);
		titleLabel.setText(TITLE_QUERY_TITLE);

		titleText = new Text(control, SWT.BORDER);
		GridData gd = new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL);
		gd.horizontalSpan = 3;
		titleText.setLayoutData(gd);
		titleText.addKeyListener(new KeyListener() {
			public void keyPressed(KeyEvent e) {
				// ignore
			}

			public void keyReleased(KeyEvent e) {
				getContainer().updateButtons();
			}
		});
	}
	
	protected Control createOptionsGroup(Composite control) {
		Group group = new Group(control, SWT.NONE);
		// group.setText("Ticket Attributes");
		GridLayout layout = new GridLayout();
		layout.numColumns = 1;
		group.setLayout(layout);
		GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
		gd.horizontalSpan = 4;
		group.setLayoutData(gd);

		createAttributeLists(group);
		//createProductAttributes(group);
		//createTicketAttributes(group);
		createUpdateButton(group);

		return group;
	}
	
	/*
	 * Creates the area for selection on product attributes component/version/milestone.
	 */
	protected Control createAttributeLists(Composite control) {
		Composite group = new Composite(control, SWT.NONE);
		GridLayout layout = new GridLayout();
		layout.numColumns = 2;
		group.setLayout(layout);
		GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
		gd.horizontalSpan = 1;
		group.setLayoutData(gd);

		Label label = new Label(group, SWT.LEFT);
		label.setText("Status");
		
		label = new Label(group, SWT.LEFT);
		label.setText("Tasklists");
		
		rtmStatusField = new ListSearchField("status");
		rtmStatusField.createControls(group, LIST_HEIGHT);
	
		rtmListsField = new ListSearchField("list");
		rtmListsField.createControls(group, LIST_HEIGHT);

		return group;
	}
	
	protected Control createUpdateButton(final Composite control) {
		Composite group = new Composite(control, SWT.NONE);
		GridLayout layout = new GridLayout(2, false);
		group.setLayout(layout);
		group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

		updateButton = new Button(group, SWT.PUSH);
		updateButton.setText("Update Attributes from Repository");
		updateButton.setLayoutData(new GridData());
		updateButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				//TODO: more code to fix
//				if (repository != null) {
//					updateAttributesFromRepository(true);
//				} else {
//					MessageDialog.openInformation(Display.getCurrent().getActiveShell(),
//							RTMUIPlugin.TITLE_MESSAGE_DIALOG, TaskRepositoryManager.MESSAGE_NO_REPOSITORY);
//				}
			}
		});

		return group;
	}
	
	private void updateAttributesFromRepository(final boolean force) {
		final RTMClient client;
		TaskRepository repository = getTaskRepository();
		RTMRepositoryConnector connector = RTMCorePlugin.getDefault().getConnector();
		client = connector.getClientManager().getRepository(repository);
		if (client != null && !client.hasAttributes() || force) {
			try {
				IRunnableWithProgress runnable = new IRunnableWithProgress() {
					public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {

						try {
							monitor.beginTask("downloading task list names", 0);
							
							client.updateAttributes();
							monitor.done();
						} catch (RTMException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
							return;
						}
					}
				};

				if (getContainer() != null) {
					getContainer().run(true, true, runnable);
					//TODO: more code to fix
//				} else if (scontainer != null) {
//					scontainer.getRunnableContext().run(true, true, runnable);
				} else {
					IProgressService service = PlatformUI.getWorkbench().getProgressService();
					service.run(true, true, runnable);
				}
			} catch (InvocationTargetException e) {
				//TODO: more code to fix
				e.printStackTrace();
				return;
			} catch (InterruptedException e) {
				return;
			}
		}
		
		rtmListsField.setValues(client.getRTMListMap().values().toArray());
		rtmStatusField.setValues(new String[] {"Incomplete", "Completed"});

		/*statusField.setValues(client.getTicketStatus());
		resolutionField.setValues(client.getTicketResolutions());
		typeField.setValues(client.getTicketTypes());
		priorityField.setValues(client.getPriorities());

		componentField.setValues(client.getComponents());
		versionField.setValues(client.getVersions());
		milestoneField.setValues(client.getMilestones());*/
	}

	@Override
	public boolean canFlipToNextPage() {
		return false;
	}
	
	@Override
	public boolean isPageComplete() {
		if (titleText != null && titleText.getText().length() > 0) {
			return true;
		}
		return false;
	}
	
	public String getQueryUrl() {
		RTMSearch search = getRTMSearch();

		StringBuilder sb = new StringBuilder();
		sb.append(search.toQuery());
		return sb.toString();
	}

	private RTMSearch getRTMSearch() {
		RTMSearch search = new RTMSearch();
		for (SearchField field : searchFieldByName.values()) {
			RTMSearchFilter filter = field.getFilter();
			if (filter != null) {
				search.addFilter(filter);
			}
		}
		return search;
	}

	@Override
	public void applyTo(IRepositoryQuery query) {
		query.setUrl(getQueryUrl());
		query.setSummary(getTitleText());
//		rtmListsField.getFilter();
		// TODO: something, anything
		//return new RTMRepositoryQuery(repository.getUrl(), getQueryUrl(), getTitleText());
	}
	
	
	private String getTitleText() {
		return (titleText != null) ? titleText.getText() : "<search>";
	}
	
	private abstract class SearchField {

		protected String fieldName;

		public SearchField(String fieldName) {
			this.fieldName = fieldName;

			if (fieldName != null) {
				assert !searchFieldByName.containsKey(fieldName);
				searchFieldByName.put(fieldName, this);
			}
		}

		public String getFieldName() {
			return fieldName;
		}

		public abstract RTMSearchFilter getFilter();

		public abstract void setFilter(RTMSearchFilter filter);

	}

	private class TextSearchField extends SearchField {

		private Combo conditionCombo;

		protected Text searchText;

		private Label label;

		//private CompareOperator[] compareOperators = { CompareOperator.CONTAINS, CompareOperator.CONTAINS_NOT};
		private CompareOperator[] compareOperators = { CompareOperator.CONTAINS};

		public TextSearchField(String fieldName) {
			super(fieldName);
		}

		public void createControls(Composite parent, String labelText) {
			if (labelText != null) {
				label = new Label(parent, SWT.LEFT);
				label.setText(labelText);
			}

			conditionCombo = new Combo(parent, SWT.SINGLE | SWT.BORDER | SWT.READ_ONLY);
			for (CompareOperator op : compareOperators) {
				conditionCombo.add(op.toString());
			}
			conditionCombo.setText(compareOperators[0].toString());

			searchText = new Text(parent, SWT.BORDER);
			GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
			// the user search field has additional controls and no fieldName
			if (fieldName != null) {
				gd.horizontalSpan = 2;
			}
			searchText.setLayoutData(gd);
		}

		public CompareOperator getCondition() {
			return compareOperators[conditionCombo.getSelectionIndex()];
		}

		public String getSearchText() {
			return searchText.getText();
		}

		public boolean setCondition(CompareOperator operator) {
			if (conditionCombo != null) {
				int i = conditionCombo.indexOf(operator.toString());
				if (i != -1) {
					conditionCombo.select(i);
					return true;
				}
			}
			return false;
		}

		public void setSearchText(String text) {
			searchText.setText(text);
		}

		@Override
		public RTMSearchFilter getFilter() {
			String text = getSearchText();
			if (text.length() == 0) {
				return null;
			}

			RTMSearchFilter newFilter = new RTMSearchFilter(getFieldName());
			newFilter.setOperator(getCondition());
			newFilter.addValue(getSearchText());
			return newFilter;
		}

		@Override
		public void setFilter(RTMSearchFilter filter) {
			setCondition(filter.getOperator());
			java.util.List<String> values = filter.getValues();
			setSearchText(values.get(0));
		}

		public void setFieldName(String fieldName) {
			this.fieldName = fieldName;
		}

	}

	private class ListSearchField extends SearchField {

		private List list;
		private Map<String, String> listMap;

		public ListSearchField(String fieldName) {
			super(fieldName);
		}

		public void setValues(Object[] items) {
			// preserve selected values
			RTMSearchFilter filter = getFilter();

			list.removeAll();
			if (items != null) {
				list.setEnabled(true);
				for (Object item : items) {
					list.add(item.toString());
				}

				// restore selected values
				if (filter != null) {
					setFilter(filter);
				}
			} else {
				list.setEnabled(false);
			}
		}

		public void createControls(Composite parent, int height) {
			list = new List(parent, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER);
			GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
			gd.heightHint = height;
			list.setLayoutData(gd);
		}

		@Override
		public RTMSearchFilter getFilter() {
			int[] indicies = list.getSelectionIndices();
			if (indicies.length == 0) {
				return null;
			}

			RTMSearchFilter newFilter = new RTMSearchFilter(getFieldName());
			newFilter.setOperator(CompareOperator.OR);
			for (int i : indicies) {
				newFilter.addValue(list.getItem(i));
			}
			return newFilter;
		}

		@Override
		public void setFilter(RTMSearchFilter filter) {
			list.deselectAll();
			java.util.List<String> values = filter.getValues();
			for (String item : values) {
				int i = list.indexOf(item);
				if (i != -1) {
					list.select(i);
				} else {
					list.add(item, 0);
					list.select(0);
				}
			}
		}

		public void selectItems(String[] items) {
			list.deselectAll();
			for (String item : items) {
				int i = list.indexOf(item);
				if (i != -1) {
					list.select(i);
				}
			}
		}

	}

	@Override
	public String getQueryTitle() {
		// TODO Auto-generated method stub
		return null;
	}
}
